#pragma once

#include "Shape.h"

class Rect: public Shape {
private:
	/*
	Default constructor, avoid using this.
	*/
	Rect();

	/*
	Get the square of the distance between the given points.
	@param	x1				Position in x of the first point.
	@param	y1				Position in y of the first point.
	@param	x2				Position in x of the second point.
	@param	y2				Position in y of the second point.
	@return	Square of the distance between the two points.
	*/
	float SqDistanceBetween(float x1, float y1, float x2, float y2) const;
	/*
	Get the square of the distance between the given points.
	@param	p1				Position of the first point.
	@param	p2				Position of the second point.
	@return	Square of the distance between the two points.
	*/
	float SqDistanceBetween(const Vector2D& p1, const Vector2D& p2) const;
	/*
	Get the distance between the given points.
	@param	x1				Position in x of the first point.
	@param	y1				Position in y of the first point.
	@param	x2				Position in x of the second point.
	@param	y2				Position in y of the second point.
	@return	Distance between the two points.
	*/
	float DistanceBetween(float x1, float y1, float x2, float y2) const;
	/*
	Get the distance between the given points.
	@param	p1				Position of the first point.
	@param	p2				Position of the second point.
	@return	Distance between the two points.
	*/
	float DistanceBetween(const Vector2D& p1, const Vector2D& p2) const;

	float width, height; // size, dimensions of the rectangle
public:
	/*
	Create a Rect with that follows the given Transform and has the given dimensions.
	@param	position		Transform to follow.
	@param	dims			Dimensions of the rectangle (width in x, height in y).
	*/
	Rect(Transform* const position, const Vector2D& dims);
	/*
	Create a Rect with that follows the given Transform and has the given dimensions.
	@param	position		Transform to follow.
	@param	w				Width of the rectangle.
	@param	h				Height of the rectangle.
	*/
	Rect(Transform* const position, float w, float h);
	/*
	Create a Rect with that follows the given Transform and has the given dimensions.
	@param	position		Transform to follow.
	@param	posOffset		Offset to apply to the Transform being followed.
	@param	dims			Dimensions of the rectangle (width in x, height in y).
	*/
	Rect(Transform* const position, const Vector2D& posOffset, const Vector2D& dims);
	/*
	Create a Rect with that follows the given Transform and has the given dimensions.
	@param	position		Transform to follow.
	@param	posOffset		Offset to apply to the Transform being followed.
	@param	w				Width of the rectangle.
	@param	h				Height of the rectangle.
	*/
	Rect(Transform* const position, const Vector2D& posOffset, float w, float h);
	/*
	Create a Rect with that follows the given Transform and has the given dimensions.
	@param	position		Transform to follow.
	@param	xOffset			Offset in x to apply to the Transform being followed.
	@param	yOffset			Offset in y to apply to the Transform being followed.
	@param	dims			Dimensions of the rectangle (width in x, height in y).
	*/
	Rect(Transform* const position, float xOffset, float yOffset, const Vector2D& dims);
	/*
	Create a Rect with that follows the given Transform and has the given dimensions.
	@param	position		Transform to follow.
	@param	xOffset			Offset in x to apply to the Transform being followed.
	@param	yOffset			Offset in y to apply to the Transform being followed.
	@param	w				Width of the rectangle.
	@param	h				Height of the rectangle
	*/
	Rect(Transform* const position, float xOffset, float yOffset, float w, float h);
	/*
	Destructor.
	*/
	~Rect();

	/*
	@return	The dimensions of the rectangle (width and height).
	*/
	Vector2D GetDimensions() const { return Vector2D(width, height); }
	/*
	@return	Width of the rectangle.
	*/
	float GetWidth() const { return width; }
	/*
	@return	Height of the rectangle.
	*/
	float GetHeight() const { return height; }
	/*
	@return	Value in y of the bottom segment of the rectangle.
	*/
	float GetBottom() const { return GetY(); }
	/*
	@return	Value in x of the left segment of the rectangle.
	*/
	float GetLeft() const { return GetX(); }
	/*
	@return	Value in y of the top segment of the rectangle.
	*/
	float GetTop() const { return GetY() + GetHeight(); }
	/*
	@return	Value in x of the right segment of the rectangle.
	*/
	float GetRight() const { return GetX() + GetWidth(); }
	/*
	Set a new width for the rectangle.
	@param	w			New width of the rectangle.
	*/
	void SetWidth(float w) { width = fabs(w); return; }
	/*
	Set a new height for the rectangle.
	@param	h			New height of the rectangle.
	*/
	void SetHeight(float h) { height = fabs(h); return; }

	/*
	Get the line that corresponds to the bottom of the rectangle (considering y goes up).
	@param	l			Line to store the data to.
	*/
	void GetBottomLine(Line& l) const;
	/*
	Get the line that corresponds to the left of the rectangle (considering y goes up).
	@param	l			Line to store the data to.
	*/
	void GetLeftLine(Line& l) const;
	/*
	Get the line that corresponds to the top of the rectangle (considering y goes up).
	@param	l			Line to store the data to.
	*/
	void GetTopLine(Line& l) const;
	/*
	Get the line that corresponds to the right of the rectangle (considering y goes up).
	@param	l			Line to store the data to.
	*/
	void GetRightLine(Line& l) const;

	/*
	Get the closest point on the rectangle's sides to the given point.
	@param	x			Coordinates in x of the location to check.
	@param	y			Coordinates in y of the location to check.
	@param	pOut		Point to store the data to.
	*/
	void GetClosestPointTo(float x, float y, Vector2D& pOut) const;
	/*
	Get the closest point on the rectangle's sides to the given point.
	@param	p			Coordinates of the location to check.
	@param	pOut		Point to store the data to.
	*/
	void GetClosestPointTo(const Vector2D& p, Vector2D& pOut) const;

	/*
	Check if a given point is inside the rectangle.
	@param	x			Position of the point in x.
	@param	y			Position of the point in y.
	@return	Wether the point is inside the rectangle or not.
	*/
	bool Contains(float x, float y) const;
	/*
	Check if a given point is inside the rectangle.
	@param	p			Position of the point.
	@return	Wether the point is inside the rectangle or not.
	*/
	bool Contains(const Vector2D& p) const;
	/*
	Check if there is a collision with the given Shape.
	@param	l			Shape to check the collision with.
	@param	hitOut		Vector to store the hit location to in case of collision.
	@return	Wether the two objects collide or not.
	*/
	bool CollidesWith(const Line* const l, Vector2D& hitOut) const;
	/*
	Check if there is a collision with the given Shape.
	@param	r			Shape to check the collision with.
	@param	hitOut		Vector to store the hit location to in case of collision.
	@return	Wether the two objects collide or not.
	*/
	bool CollidesWith(const Rect* const r, Vector2D& hitOut) const;
	/*
	Check if there is a collision with the given Shape.
	@param	c			Shape to check the collision with.
	@param	hitOut		Vector to store the hit location to in case of collision.
	@return	Wether the two objects collide or not.
	*/
	bool CollidesWith(const Circ* const c, Vector2D& hitOut) const;
	/*
	Check if there is a collision with the given Shape.
	@param	p			Shape to check the collision with.
	@param	hitOut		Vector to store the hit location to in case of collision.
	@return	Wether the two objects collide or not.
	*/
	bool CollidesWith(const Poly* const p, Vector2D& hitOut) const;

	/*
	DO NOT USE THIS METHOD.
	*/
	void Draw() const;
	/*
	Display the rectangle information in the console.
	*/
	void COut() const;
};

